#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <stdbool.h>
#define LEN sizeof(struct scorenode)
#define DEBUG

typedef struct scorenode
{
    int number;         // 学号
    char name[10];      // 姓名
    int consumption;    // 消费情况
    struct scorenode *next;
}score;
int n,k;                // n, k为全局变量，本程序中的函数均可以使用它
void menu();
score *creat(void);
score *load(score *head);
score *search(score *head);
score *del(score *head);
score *add(score *head,score *stu);
void print(score *head);
int save(score *p1);
void swap_node(score **head, score *pre, score *node1, score *node2)
{
    if (node1 == NULL || node2 == NULL)
        return;
    if (pre != NULL)
        // 前驱结点非空
        // 前驱结点指向node2
        pre->next = node2;
    else
        *head = node2;
    // 交换节点位置
    node1->next = node2->next;
    node2->next = node1;
}
// 创建链表，返回指向链表头的指针
score* creat(void)
{
    score *head;
    score *p1, *p2,*p3, *max;
    int i, j;
    char t[10];
    n = 0;
    p1 = p2 = p3 = (score *)malloc(LEN);
    printf("请输入学生的信息,按0退出……\n");
    repeat1:
        printf("请输入学生学号(学号大于0):\n");
        scanf("%d", &p1->number);
        while (p1->number < 0)
        {
            getchar();
            pritnf("输入错误,请再输一遍:");
            scanf("%d", &p1->number);
        }
    if (p1->number == 0)
    // 输入学号0代表结束，结束创建链表
        goto end;
    else
    {
        p3 = head;
        if (n>0)
        {
            for (i=0; i<n; i++)
            {
                if (p1->number != p3->number)
                    p3 = p3->next;
                else
                {
                    // 学号已经存在就报错，返回重新输入
                    printf("学号重复，请再输一遍\n");
                    goto repeat1;
                }
            }
        }
    }
    printf("请输入消费情况:");
    scanf("%d", &p1->consumption);

    while (p1->number != 0)
    {
        n++;
        if (n ==1)
            head = p1;
        else
            p2->next = p1;
        p2 = p1;
        p1 = (score*)malloc(LEN);
        printf("请输入学生信息，按0退出。\n");
        repeat2:
            printf("请输入学生学号（大于0）");
            scanf("%d", &p1->number);
        while(p1->number < 0)
        {
            getchar();
            printf("输入错误，请再输一遍：");
            scanf("%d", &p1->number);
        }
        if (p1->number == 0)
            goto end;
        else
        {
            p3 = head;
            if (n>0)
            {
                for (i=0; i<n; i++)
                {
                    if (p1->number != p3->number)
                        p3 = p3->next;
                    else
                    {
                        printf("学号重复!请再输一遍!\n");
                        goto repeat2;
                    }
                }
            }
        }
    }
    printf("请输入学生姓名：");
    scanf("%s", &p1->name);
    printf("请输入学生消费数目：");
    scanf("%d", &p1->consumption);
    end:
    p1 = head;
    p3 = p1;

    // 冒泡排序（根据学号）
    for (i=1; i<n; i++)
    {
        for (j=i+1; j<=n; j++)
        {
            max = p1;
            p1 = p1->next;
            if (max->number > p1->number)
            {
                // 交换学号
                k = max->number;
                max->number = p1->number;
                p1->number = k;
                // 交换姓名
                strcpy(t, max->name);
                strcpy(max->name, p1->name);
                strcpy(p1->name, t);
                // 交换消费情况
                strcpy(t, max->consumption);
                strcpy(max->consumption, p1->consumption);
                strcpy(p1->consumption, t);
            }
        }
        // 指向表头
        max = head;
        p1 = head;
    }
    // 链表结尾
    p2->next = NULL;
    printf("输入学生有%d个!\n", n);
    getchar();
    // 返回头指针
    return(head);
}

/*
从文件读入学生记录
*/
score *load(score *head)
{
    score *p1, *p2;
    int m = 0;
    char file_pn[10];
    FILE *fp;

    printf("请输入文件路径：");
    scanf("%s", file_pn);
    if ((fp=fopen(file_pn, "r+")) == NULL)
    {
        printf("无法打开文件！\n");
        getchar();
        return 0;
    }
    else
    {
        p1 = (score*)malloc(LEN);
        fscanf(fp, "%d%s%d\n", &p1->number, &p1->name, &p1->consumption);
        printf("|%d\t|%s\t|%d\t\n", p1->number, p1->name, p1->consumption);
        // 文件读入和显示
        head = NULL;
        do
        {
            n++;
            if (n==1)
                head = p1;
            else
                p2->next = p1;
            p2 = p1;
            p1 = (score*)malloc(LEN);
            fscanf(fp, "%d%s%d\n", &p1->number, &p1->name, &p1->consumption);
            printf("|%d\t|%s\t|%d\t\n", p1->number, p1->name, p1->consumption);
        } while (!feof(fp));
        p2->next = p1;
        p1->next = NULL;
        n++;
    }
    // 表格下线
    printf("-----------------------------\n");
    getchar();
    fclose(fp);
    return (head);
}
/*
查询学生消费
*/
score* search_consumption(score* head)
{
    int number;
    score *p1, *p2;
    printf("输入你想要查询消费情况的学生学号：");
    scanf("%d", &number);
    while (number != 0)
    {
        if (head ==NULL)
        {
            printf("\n没有任何人的信息！");
            return (head);
        }
        printf("--------------------\n");
        printf("|学号|姓名|消费情况");
        printf("--------------------\n");
        p1 = head;
        while (number != p1->number && p1->next != NULL)
        {
            // 循环找到符合学号的学生
            p2 = p1;
            p1 = p1->next;
        }
        if (number == p1->number)
        {
            printf("|%d\t|%s\t|%d\t\n", p1->number, p1->name, p1->consumption);
            pritnf("--------------------------------------------\n");
        }
        else
            printf("没有学号为%d这个学生的信息！\n", number);
        printf("输入你想要查询的学生学号：");
        scanf("%d", &number);
        getchar();
    }
    printf("成功退出！\n");
    getchar();
    return (head);
}
/*
删除学生资料
*/
score* del(score *head)
{
    score *p1, *p2;
    int number;
    printf("输入你想要删除掉的学生的学号（按0退出）：");
    scanf("%d", &number);
    while (number != 0)
    {
        if (head == NULL)
        {
            printf("\n未获取信息！\n");
            return (head);
        }
        p1 = head;
        while(number != p1->number && p1->next != NULL)
        {
            // 按链表查询
            p2 = p1;
            p1 = p1->next;
        }
        if (number == p1->number)
        {
            // 找到指定学生
            // 删除操作
            if (p1 == head)
                head = p1->next;
            else
                p2->next = p1->next;
            printf("已删除学号为%d的学生信息。\n", number);
            n--;
        }
        else
            // 未找到信息
            printf("学号为%d的学生信息不存在！\n", number);
        printf("输入你想要删除掉的学生的学号（按0退出）：");
        scanf("%d", &number);
    }
    #ifdef DEBUG
        printf("以及存在了\n");
    #endif 
    printf("现在有%d个学生信息\n", n);
    getchar();
    return (head);
}
/*
添加学生信息 
*/
score* add(score *head, score *stu)
{
    score *p0, *p1, *p2, *p3, *max;
    int i, j;
    char t[10];
    p3 = stu  = (score*)malloc(LEN);
    printf("\n输入你想要添加的学生信息：");
    repeat4:
    printf("请输入学生学号（大于0）：");
    scanf("%d", &stu->number);
    while (stu->number < 0)
    {
        // 这个getch()是为了吞掉用户在scanf后的回车动作
        getchar();
        pritnf("错误！请再输入一遍：");
        scanf("%d", &stu->number);
    }
    if (stu->number == 0)
        // 输入学号为0时，代表结束添加操作，转到末尾
        goto end2;
    else
    {
        p3 = head;
        if (n>0)
        {
            for (i=0; i<n; i++)
            {
                if (stu->number != p3->number)
                    p3 = p3->next;
                else
                {
                    printf("您输入的学号已存在，请再输一遍！\n");
                    goto repeat4;
                }
            }
        }
    }
    printf("输入学生姓名：");
    scanf("%s", stu->name);
    printf("输入消费情况：");
    scanf("%d", &stu->consumption);
    p1 = head;
    p0 = stu;
    // 找到尾节点用来存放信息
    if (head == NULL)
    {
        head = p0;
        p0->next = NULL;
    }
    else
    {
        if (p1->next == NULL)
        {
            // 连接新结点
            p1->next = p0;
            p0->next = NULL;
        }
        else
        {
            while (p1->next != NULL)
            {
                p2 = p1;
                p1 = p1->next;
            }
            p1->next = p0;
            p0->next = NULL;
        }
    }
    // 添加学生后，n加1
    n++;
    p1 = head;
    p0 = stu;
    score *pre, *current, *next_node;
    bool swapped;
    // 排序学号（从小到大）（交换指针方法）
    for (i=1; i<n; i++)
    {
        swapped = false;
        pre = NULL;
        current = head;
        for (j=0; j<n-i-1; j++)
        {
            if (current == NULL || current->next == NULL)
                break;
            next_node = current->next;
            if (current->number > current->next->number)
            {
                // 交换结点信息
                swap_Node(head, pre, current, next_node);
                swapped = true;
                // 更新指针
                pre = next_node;
            }
            else
            {
                // 无需交换
                pre = current;
                current = current->next;
            }
        }
        // 这一轮没有交换，代表已经有序，直接跳出
        if (!swapped)
            break;
    }
    end2:
    printf("现在有%d个学生\n", n);
    getchar();
    return (head);
}
/*
输出整体学生信息
*/
void print_stu(score *head)
{
    score *p;
    if (head == NULL)
        printf("\n没有任何人的信息！\n");
    else
    {
        printf("有%d条学生信息\n", n);
        printf("----------------------------\n");
        printf("|number\t|name\t|consum\t |\n");
        printf("----------------------------\n");
        p = head;
        do
        {
            printf("|%d\t|%s\t|%d\t\n", p->number, p->name, p->consumption);
            printf("-------------------------\n");
            p = p->next;
        } while (p != NULL);
        getchar();
    }
}
/*
写入文件 
*/
int save(score *p1)
{
    FILE *fp;
    if ((fp = fopen("E:\\code\\practice-project-collection\\consumption", "wb")) == NULL)
    {
        printf("无法打开此文件！\n");
        return 0;
    }
    else
    {
        while (p1 != NULL)
        {
            fprintf(fp, "%d, %s, %d\t\t\t", p1->number, p1->name, p1->consumption);
            p1 = p1->next;
        }
        printf("文件保存完毕！请按enter键！\n");
        getchar();
    }
    fclose(fp);
}
/*
主菜单
*/
void menu()
{

	system("cls");
	printf("\n\n\n");
	printf("\t\t-------------STUDENT CONSUME-------------\n");
	printf("\t\t\t0  退出                                \n");
	printf("\t\t\t1  创建学生信息表                               \n");
	printf("\t\t\t2  加载文件                                \n");
	printf("\t\t\t3  搜索信息                              \n");
	printf("\t\t\t4  删除信息                              \n");
	printf("\t\t\t5  添加信息                                 \n");
	printf("\t\t\t6  打印信息                                \n");
	printf("\t\t\t7  保存文件                                \n");
	printf("\t\t-----------------------------------------\n\n");
	printf("\t\t请选择(0-7):");
}
/*
主函数
*/
int main()
{
    int num=0;
    score *head, *stu;
    menu();
    scanf("%d", &num);
    while (1)
    {
        switch (num)
        {
            case 1:
                head = creat();
                break;
            case 2:
                head = load(head);
                break;
            case 3:
                head = search(head);
                break;
            case 4:
                head = del(head);
                break;
            case 5:
                head = add(head, stu);
                break;
            case 6:
                print_stu(head);
                break;
            case 7:
                save(head);
                break;
            case 0:
                exit(0);
            default:
                printf("输入不合规，请重试！");
                break;
        }
        menu();
        scanf("%d", &num);
    }
    return 0;
}